// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.web.browser.dom;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.internal.ole.win32.COM;
import org.eclipse.swt.internal.ole.win32.IDispatch;
import org.eclipse.swt.internal.ole.win32.IUnknown;

/**
 * Document Object Model context, we can use this to retrieve or create or children easily. It must be reset for a new
 * DOM.
 * 
 * @author jliu
 */
public class DocumentContext {

    /**
     * A nodes cache to retrieve.
     */
    private final Map<Integer, Node> nodesCache;

    /**
     * Document Object Model context, we can use this to retrieve or create or children easily. It must be reset for a
     * new DOM.
     */
    public DocumentContext() {
        nodesCache = new HashMap<Integer, Node>();
    }

    /**
     * Get a NodeList by using current dispatch.
     * 
     * @param dispatch
     * @return
     */
    public synchronized NodeList getNodeList(IDispatch dispatch) {
        Integer uniqueID = getUniqueID(dispatch);
        NodeList nodeList = (NodeList) nodesCache.get(uniqueID);
        if (nodeList == null) {
            nodeList = ElementFactory.createNodeList(dispatch, this);
            nodesCache.put(uniqueID, nodeList);
        }
        return nodeList;
    }

    /**
     * Get HTML Document element .
     * 
     * @param dispatch
     * @return
     */
    public synchronized HTMLDocument getDocument(IDispatch dispatch) {
        HTMLDocument document = ElementFactory.createDocument(dispatch, this);
        nodesCache.put(getUniqueID(dispatch), document);
        return document;
    }

    /**
     * Get a HTML Element node.
     * 
     * @param dispatch
     * @return
     */
    public synchronized Node getNode(IDispatch dispatch) {
        Integer uniqueID = getUniqueID(dispatch);
        Node node = nodesCache.get(uniqueID);
        if (node == null) {
            node = ElementFactory.createNode(dispatch, this);
            nodesCache.put(uniqueID, node);
        }
        return node;
    }

    /**
     * Get the id of this node object, this is usually a unique value .
     */
    private synchronized Integer getUniqueID(IDispatch dispatch) {
        int ppvUnknown[] = new int[1];
        dispatch.QueryInterface(COM.IIDIUnknown, ppvUnknown);
        Integer uniqID = new Integer(ppvUnknown[0]);
        (new IUnknown(ppvUnknown[0])).Release();
        return uniqID;
    }

    /**
     * Reset the nodesCache to accept new document element.
     */
    public synchronized void reset() {
        dispose();
        nodesCache.clear();
    }

    /**
     * Dispose all old IDispatchs.
     */
    public synchronized void dispose() {
        Collection<Node> values = nodesCache.values();
        for (Node node : values) {
            node.Release();
        }
    }
}
